home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / pc / files / amiga / rhinosrc.lha / tcpsock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-23  |  7.5 KB  |  361 lines

  1. #include "global.h"
  2. #include "tcp.h"
  3. #include "socket.h"
  4. #include "usock.h"
  5.  
  6. static void s_trcall __ARGS((struct tcb *tcb,int cnt));
  7. static void s_tscall __ARGS((struct tcb *tcb,int old,int new));
  8. static void s_ttcall __ARGS((struct tcb *tcb,int cnt));
  9. static void trdiscard __ARGS((struct tcb *tcb,int cnt));
  10. static void autobind __ARGS((struct usock *up));
  11.  
  12. int16 Lport = 1024;
  13.  
  14. int
  15. so_tcp(up,protocol)
  16. struct usock *up;
  17. int protocol;
  18. {
  19.     up->type = TYPE_TCP;
  20.     return 0;
  21. }
  22. int
  23. so_tcp_listen(up,backlog)
  24. struct usock *up;
  25. int backlog;
  26. {
  27.     int s;
  28.     struct sockaddr_in *local;
  29.     struct socket lsock;
  30.  
  31.     s = up->index;
  32.     if(up->name == NULLCHAR)
  33.         autobind(up);
  34.  
  35.     local = (struct sockaddr_in *)up->name;
  36.     lsock.address = local->sin_addr.s_addr;
  37.     lsock.port = local->sin_port;
  38.     up->cb.tcb = open_tcp(&lsock,NULLSOCK,
  39.      backlog ? TCP_SERVER:TCP_PASSIVE,0,
  40.     s_trcall,s_ttcall,s_tscall,up->tos,s);
  41.     return 0;
  42. }
  43. int
  44. so_tcp_conn(up)
  45. struct usock *up;
  46. {
  47.     int s;
  48.     struct tcb *tcb;
  49.     struct socket lsock,fsock;
  50.     struct sockaddr_in *local,*remote;
  51.  
  52.     if(up->name == NULLCHAR){
  53.         autobind(up);
  54.     }
  55.     if(checkipaddr(up->peername,up->namelen) == -1){
  56.         errno = EAFNOSUPPORT;
  57.         return -1;
  58.     }
  59.     s = up->index;
  60.     /* Construct the TCP-style ports from the sockaddr structs */
  61.     local = (struct sockaddr_in *)up->name;
  62.     remote = (struct sockaddr_in *)up->peername;
  63.  
  64.     if(local->sin_addr.s_addr == INADDR_ANY)
  65.         /* Choose a local address */
  66.         local->sin_addr.s_addr = locaddr(remote->sin_addr.s_addr);
  67.  
  68.     lsock.address = local->sin_addr.s_addr;
  69.     lsock.port = local->sin_port;
  70.     fsock.address = remote->sin_addr.s_addr;
  71.     fsock.port = remote->sin_port;
  72.  
  73.     /* Open the TCB in active mode */
  74.     if (up->cb.tcb == NULL)    /* make it restartable after EWOULDBLOCK -Rhialto */
  75.         up->cb.tcb = open_tcp(&lsock,&fsock,TCP_ACTIVE,0,
  76.          s_trcall,s_ttcall,s_tscall,up->tos,s);
  77.  
  78.     /* Wait for the connection to complete */
  79.     while((tcb = up->cb.tcb) != NULLTCB && tcb->state != TCP_ESTABLISHED){
  80.         if(up->noblock){
  81.             errno = EWOULDBLOCK;
  82.             return -1;
  83.         } else if((errno = pwait(up)) != 0){
  84.             return -1;
  85.         }
  86.     }
  87.     if(tcb == NULLTCB){
  88.         /* Probably got refused */
  89.         free(up->peername);
  90.         up->peername = NULLCHAR;
  91.         errno = ECONNREFUSED;
  92.         return -1;
  93.     }
  94.     return 0;
  95. }
  96. int
  97. so_tcp_recv(up,bpp,from,fromlen)
  98. struct usock *up;
  99. struct mbuf **bpp;
  100. char *from;
  101. int *fromlen;
  102. {
  103.     int cnt;
  104.     struct tcb *tcb;
  105.  
  106.     while((tcb = up->cb.tcb) != NULLTCB && tcb->r_upcall != trdiscard
  107.      && (cnt = recv_tcp(tcb,bpp,(int16)0)) == -1){
  108.         if(up->noblock){
  109.             errno = EWOULDBLOCK;
  110.             return -1;
  111.         } else if((errno = pwait(up)) != 0){
  112.             return -1;
  113.         }
  114.     }
  115.     if(tcb == NULLTCB){
  116.         /* Connection went away */
  117.         errno = ENOTCONN;
  118.         return -1;
  119.     } else if(tcb->r_upcall == trdiscard){
  120.         /* Receive shutdown has been done */
  121.         errno = ENOTCONN;    /* CHANGE */
  122.         return -1;
  123.     }
  124.     return cnt;
  125. }
  126. int
  127. so_tcp_send(up,bp,to)
  128. struct usock *up;
  129. struct mbuf *bp;
  130. char *to;
  131. {
  132.     struct tcb *tcb;
  133.     int cnt;
  134.  
  135.     if((tcb = up->cb.tcb) == NULLTCB){
  136.         free_p(bp);
  137.         errno = ENOTCONN;
  138.         return -1;
  139.     }        
  140.     cnt = send_tcp(tcb,bp);
  141.  
  142.     while((tcb = up->cb.tcb) != NULLTCB &&
  143.      tcb->sndcnt > tcb->window){
  144.         /* Send queue is full */
  145.         if(up->noblock){
  146.             errno = EWOULDBLOCK;
  147.             return -1;
  148.         } else if((errno = pwait(up)) != 0){
  149.             return -1;
  150.         }
  151.     }
  152.     if(tcb == NULLTCB){
  153.         errno = ENOTCONN;
  154.         return -1;
  155.     }
  156.     return cnt;
  157. }
  158. int
  159. so_tcp_qlen(up,rtx)
  160. struct usock *up;
  161. int rtx;
  162. {
  163.     int len;
  164.  
  165.     switch(rtx){
  166.     case 0:
  167.         len = up->cb.tcb->rcvcnt;
  168.         break;
  169.     case 1:
  170.         len = up->cb.tcb->sndcnt;
  171.         break;
  172.     }
  173.     return len;
  174. }
  175. int
  176. so_tcp_kick(up)
  177. struct usock *up;
  178. {
  179.     kick_tcp(up->cb.tcb);
  180.     return 0;
  181. }
  182. int
  183. so_tcp_shut(up,how)
  184. struct usock *up;
  185. int how;
  186. {
  187.     switch(how){
  188.     case 0:    /* No more receives -- replace upcall */
  189.         up->cb.tcb->r_upcall = trdiscard;
  190.         break;
  191.     case 1:    /* Send EOF */
  192.         close_tcp(up->cb.tcb);
  193.         break;
  194.     case 2:    /* Blow away TCB */
  195.         reset_tcp(up->cb.tcb);
  196.         up->cb.tcb = NULLTCB;
  197.         break;
  198.     }
  199.     return 0;
  200. }
  201. int
  202. so_tcp_close(up)
  203. struct usock *up;
  204. {
  205.     if(up->cb.tcb != NULLTCB){    /* In case it's been reset */
  206.         up->cb.tcb->r_upcall = trdiscard;
  207.         /* Tell the TCP_CLOSED upcall there's no more socket */
  208.         up->cb.tcb->user = -1;
  209.         close_tcp(up->cb.tcb);
  210.     }
  211.     return 0;
  212. }
  213. /* TCP receive upcall routine */
  214. static void
  215. s_trcall(tcb,cnt)
  216. struct tcb *tcb;
  217. int cnt;
  218. {
  219.     /* Wake up anybody waiting for data, and let them run */
  220.     psignal(itop(tcb->user),1);
  221.     pwait(NULL);
  222. }
  223. /* TCP transmit upcall routine */
  224. static void
  225. s_ttcall(tcb,cnt)
  226. struct tcb *tcb;
  227. int cnt;
  228. {
  229.     /* Wake up anybody waiting to send data, and let them run */
  230.     psignal(itop(tcb->user),1);
  231.     pwait(NULL);
  232. }
  233. /* TCP state change upcall routine */
  234. static void
  235. s_tscall(tcb,old,new)
  236. struct tcb *tcb;
  237. int old,new;
  238. {
  239.     int s,ns;
  240.     struct usock *up,*nup,*oup;
  241.     union sp sp;
  242.  
  243.     s = tcb->user;
  244.     oup = up = itop(s);
  245.  
  246.     switch(new){
  247.     case TCP_CLOSED:
  248.         /* Clean up. If the user has already closed the socket,
  249.          * then up will be null (s was set to -1 by the close routine).
  250.          * If not, then this is an abnormal close (e.g., a reset)
  251.          * and clearing out the pointer in the socket structure will
  252.          * prevent any further operations on what will be a freed
  253.          * control block. Also wake up anybody waiting on events
  254.          * related to this tcb so they will notice it disappearing.
  255.          */
  256.         if(up != NULLUSOCK){
  257.             up->cb.tcb = NULLTCB;
  258.             up->errcodes[0] = tcb->reason;
  259.             up->errcodes[1] = tcb->type;
  260.             up->errcodes[2] = tcb->code;
  261.         }
  262.         del_tcp(tcb);
  263.         break;
  264.     case TCP_SYN_RECEIVED:
  265.         /* Handle an incoming connection. If this is a server TCB,
  266.          * then we're being handed a "clone" TCB and we need to
  267.          * create a new socket structure for it. In either case,
  268.          * find out who we're talking to and wake up the guy waiting
  269.          * for the connection.
  270.          */
  271.         if(tcb->flags.clone){
  272.             /* Clone the socket */
  273.             ns = socket(AF_INET,SOCK_STREAM,0);
  274.             nup = itop(ns);
  275.             ASSIGN(*nup,*up);
  276.             tcb->user = ns;
  277.             nup->cb.tcb = tcb;
  278.             /* Allocate new memory for the name areas */
  279.             nup->name = mallocw(SOCKSIZE);
  280.             nup->peername = mallocw(SOCKSIZE);
  281.             nup->index = ns;
  282.             /* Store the new socket # in the old one */
  283.             up->rdysock = ns;
  284.             up = nup;
  285.             s = ns;
  286.         } else {
  287.             /* Allocate space for the peer's name */
  288.             up->peername = mallocw(SOCKSIZE);
  289.             /* Store the old socket # in the old socket */
  290.             up->rdysock = s;
  291.         }
  292.         /* Load the addresses. Memory for the name has already
  293.          * been allocated, either above or in the original bind.
  294.          */
  295.         sp.p = up->name;
  296.         sp.in->sin_family = AF_INET;
  297.         sp.in->sin_addr.s_addr = up->cb.tcb->conn.local.address;
  298.         sp.in->sin_port = up->cb.tcb->conn.local.port;
  299.         up->namelen = SOCKSIZE;
  300.  
  301.         sp.p = up->peername;
  302.         sp.in->sin_family = AF_INET;
  303.         sp.in->sin_addr.s_addr = up->cb.tcb->conn.remote.address;
  304.         sp.in->sin_port = up->cb.tcb->conn.remote.port;
  305.         up->peernamelen = SOCKSIZE;
  306.  
  307.         /* Wake up the guy accepting it, and let him run */
  308.         psignal(oup,1);
  309.         pwait(NULL);
  310.         break;
  311.     default:    /* Ignore all other state transitions */
  312.         break;
  313.     }
  314.     psignal(up,0);    /* In case anybody's waiting */
  315. }
  316. /* Discard data received on a TCP connection. Used after a receive shutdown or
  317.  * close_s until the TCB disappears.
  318.  */
  319. static void
  320. trdiscard(tcb,cnt)
  321. struct tcb *tcb;
  322. int cnt;
  323. {
  324.     struct mbuf *bp;
  325.  
  326.     recv_tcp(tcb,&bp,(int16)cnt);
  327.     free_p(bp);
  328. }
  329.  
  330. /* Issue an automatic bind of a local address */
  331. static void
  332. autobind(up)
  333. struct usock *up;
  334. {
  335.     struct sockaddr_in local;
  336.     int s;
  337.  
  338.     s = up->index;
  339.     local.sin_family = AF_INET;
  340.     local.sin_addr.s_addr = INADDR_ANY;
  341.     local.sin_port = Lport++;
  342.     bind(s,(char *)&local,sizeof(struct sockaddr_in));
  343. }
  344. char *
  345. tcpstate(up)
  346. struct usock *up;
  347. {
  348.     if(up->cb.tcb == NULLTCB)
  349.         return NULLCHAR;
  350.     return Tcpstates[up->cb.tcb->state];
  351. }
  352. int
  353. so_tcp_stat(up)
  354. struct usock *up;
  355. {
  356.     st_tcp(up->cb.tcb);
  357.     return 0;
  358. }
  359.  
  360.  
  361.